using System;
using System.Runtime.InteropServices;


namespace svs.Mobile.BeyondScheduler
{

    public class Telephony : IDisposable
    {
        IntPtr hLineApp;
        IntPtr hLine;

			 public static void TurnFlightModeOn()
			 {
			 	Telephony t = new Telephony();
			 	t.PhoneEnabled = false;
			 }

			public static void TurnFlightModeOff()
			{
				Telephony t = new Telephony();
				t.PhoneEnabled = true;
			}

        public Telephony()
        {
            int numDevices;
            int version = 0x20000;
            LINEINITIALIZEEXPARAMS initParams = new LINEINITIALIZEEXPARAMS();
            initParams.dwTotalSize = Marshal.SizeOf(initParams);
            initParams.dwOptions = LINEINITIALIZEEXOPTION.USEEVENT;

            //initialize tapi - negotiates api version and returns number of devices
            int result = lineInitializeEx(out hLineApp, GetModuleHandle(null), 0, "MobileScheduler", out numDevices, ref version, ref initParams);
            int cellularLineIndex = 0;

            //loop through the devices looking for the cellular line
            for(int thisDevice = 0; thisDevice < numDevices; thisDevice++)
            {

                byte[] caps = new byte[Marshal.SizeOf(typeof(LINEDEVCAPS))+256];
                BitConverter.GetBytes(caps.Length).CopyTo(caps,0);
                //caps.dwTotalSize = Marshal.SizeOf(caps);

                result = lineGetDevCaps(hLineApp, thisDevice, 0x020000, 0, caps);
                //length of the null terminated line name
                int namelen = BitConverter.ToInt32(caps, 32);
                //offset in the buffer of the line name
                int nameoffset = BitConverter.ToInt32(caps,36);
                //get the line name
                string lineName = System.Text.Encoding.Unicode.GetString(caps, nameoffset, namelen);

                //strip the trailing null if present
                int nullIndex = lineName.IndexOf('\0');
                if (nullIndex > -1)
                {
                    lineName = lineName.Substring(0, nullIndex);
                }

                //if cellular line store the index and leave the loop
                if (lineName == "Cellular Line")
                {
                    cellularLineIndex = thisDevice;
                    break;
                }
            }

            //open a handle to the cellular line
            result = lineOpen(hLineApp, cellularLineIndex, out hLine, version, 0, 0, LINECALLPRIVILEGE.NONE , LINEMEDIAMODE.INTERACTIVEVOICE, IntPtr.Zero);

        }

        public bool PhoneEnabled
        {
            get
            {
                LINEEQUIPSTATE state;
                LINERADIOSUPPORT radio;
                lineGetEquipmentState(hLine, out state, out radio);

                if (state == LINEEQUIPSTATE.FULL)
                {
                    return true;
                }

                return false;
            }
            set
            {
                if (value)
                {
                    lineSetEquipmentState(hLine, LINEEQUIPSTATE.FULL);
                    lineRegister(hLine, LINEREGMODE.AUTOMATIC, null, 0);
                }
                else
                {
                    lineUnregister(hLine);
                    lineSetEquipmentState(hLine, LINEEQUIPSTATE.MINIMUM);
                }
            }
        }

        ~Telephony()
        {
            Dispose(false);
        }


        #region IDisposable Members

        protected void Dispose(bool disposing)
        {
            if (hLine != IntPtr.Zero)
            {
                lineClose(hLine);
                hLine = IntPtr.Zero;
            }

            if (hLineApp != IntPtr.Zero)
            {
                lineShutdown(hLineApp);
                hLineApp = IntPtr.Zero;
            }
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        #endregion

        [DllImport("coredll", SetLastError = true)]
        internal static extern IntPtr GetModuleHandle(string lpModuleName);

      

        //TAPI

        [DllImport("coredll", SetLastError = true)]
        internal static extern int lineInitializeEx(out IntPtr lphLineApp, IntPtr hInstance, int lpfnCallback, string lpszFriendlyAppName, out int lpdwNumDevs, ref int lpdwAPIVersion, ref LINEINITIALIZEEXPARAMS lpLineInitializeExParams);

        public struct LINEINITIALIZEEXPARAMS
        {
            public int dwTotalSize;
            public int dwNeededSize;
            public int dwUsedSize;
            public LINEINITIALIZEEXOPTION dwOptions;
            public IntPtr handle;
            public int dwCompletionKey;
        }

        public enum LINEINITIALIZEEXOPTION
        {
            USECOMPLETIONPORT = 0x00000003,
            USEEVENT = 0x00000002,
            USEHIDDENWINDOW = 0x00000001,
        }

        [DllImport("coredll", SetLastError = true)]
        internal static extern int lineShutdown(IntPtr hLineApp);

        [DllImport("coredll", SetLastError = true)]
        internal static extern int lineGetDevCaps(IntPtr hLineApp, int dwDeviceID, int dwAPIVersion, int dwExtVersion, byte[] lpLineDevCaps);

        [DllImport("coredll", SetLastError = true)]
        internal static extern int lineOpen(IntPtr hLineApp, int dwDeviceID, out IntPtr lphLine, int dwAPIVersion, int dwExtVersion, int dwCallbackInstance, LINECALLPRIVILEGE dwPrivileges, LINEMEDIAMODE dwMediaModes, IntPtr lpCallParams);

        internal enum LINECALLPRIVILEGE
        {
            NONE = 0x00000001,
            MONITOR = 0x00000002,
            //OWNER = 0x00000004,
        }

        [Flags()]
        internal enum LINEMEDIAMODE
        {
            //UNKNOWN = 0x00000002,
            INTERACTIVEVOICE = 0x00000004,
        }

        [DllImport("coredll", SetLastError = true)]
        internal static extern int lineClose(IntPtr hLine);

        //extended TAPI

        [DllImport("cellcore", SetLastError = true)]
        internal static extern int lineSetEquipmentState(IntPtr hLine, LINEEQUIPSTATE dwState);

        internal enum LINEEQUIPSTATE : int
        {
            MINIMUM = 0x00000001,
            RXONLY = 0x00000002,
            TXONLY = 0x00000003,
            NOTXRX = 0x00000004,
            FULL = 0x00000005,
        }

        internal enum LINERADIOSUPPORT : int
        {
            OFF = 0x00000001,
            ON = 0x00000002,
            UNKNOWN = 0x00000003,
        }

        [DllImport("cellcore", SetLastError = true)]
        internal static extern int lineGetEquipmentState(IntPtr hLine, out LINEEQUIPSTATE lpdwState, out LINERADIOSUPPORT lpdwRadioSupport);

        [DllImport("cellcore", SetLastError = true)]
        internal static extern int lineRegister(IntPtr hLine, LINEREGMODE dwRegisterMode, string lpszOperator, int dwOperatorFormat);

        internal enum LINEREGMODE
        {
            AUTOMATIC = 0x00000001,
        }

        [DllImport("cellcore", SetLastError = true)]
        internal static extern int lineUnregister(IntPtr hLine);

        public struct LINEDEVCAPS
        {
            public int dwTotalSize;
            public int dwNeededSize;
            public int dwUsedSize;
            public int dwProviderInfoSize;
            public int dwProviderInfoOffset;
            public int dwSwitchInfoSize;
            public int dwSwitchInfoOffset;
            public int dwPermanentLineID;
            public int dwLineNameSize;
            public int dwLineNameOffset;
            public int dwStringFormat; 
            public int dwAddressModes;
            public int dwNumAddresses;
            public int dwBearerModes;
            public int dwMaxRate;
            public int dwMediaModes;
            public int dwGenerateToneModes;
            public int dwGenerateToneMaxNumFreq;
            public int dwGenerateDigitModes;
            public int dwMonitorToneMaxNumFreq;
            public int dwMonitorToneMaxNumEntries;
            public int dwMonitorDigitModes;
            public int dwGatherDigitsMintimeout;
            public int dwGatherDigitsMaxTimeout;
            public int dwMedCtlDigitMaxListSize;
            public int dwMedCtlMediaMaxListSize;
            public int dwMedCtlToneMaxListSize;
            public int dwMedCtlCallStateMaxListSize;
            public int dwDevCapFlags;
            public int dwMaxNumActiveCalls;
            public int dwAnswerMode;
            public int dwRingModes;
            public int dwLineStates;
            public int dwUUIAcceptSize;
            public int dwUUIAnswerSize;
            public int dwUUIMakeCallSize;
            public int dwUUIDropSize;
            public int dwUUISendUserUserInfoSize;
            public int dwUUICallInfoSize;
            //LINEDIALPARAMS MinDialParams;
            //LINEDIALPARAMS MaxDialParams;
            //LINEDIALPARAMS DefaultDialParams;
            public int dwNumTerminals;
            public int dwTerminalCapsSize;
            public int dwTerminalCapsOffset;
            public int dwTerminalTextEntrySize;
            public int dwTerminalTextSize;
            public int dwTerminalTextOffset;
            public int dwDevSpecificSize;
            public int dwDevSpecificOffset;
            public int dwLineFeatures;
            public int dwSettableDevStatus;
            public int dwDeviceClassesSize;
            public int dwDeviceClassesOffset;
        }

        public struct LINEDIALPARAMS
        {
            public int dwDialPause; 
            public int dwDialSpeed; 
            public int dwDigitDuration; 
            public int dwWaitForDialtone; 
        }
    }
}
